﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;

namespace MillsClient
{
    public class AsynchronoiusIOClient
    {
        private Socket _clientSocket;
        private int _portOfServer;
        IPEndPoint _remoteEndPoint = null;
        ConnectionInfo _clientConnection = null;//new ConnectionInfo();
        string _localMachineIP = null;
        string _serverIP = null;

        public string responce;

        public class ConnectionInfo
        {
            public const int BufferSize = 255;
            public Socket ConnSocket;
            public byte[] Buffer = new byte[BufferSize];
            public string recieveBuffer = string.Empty;
        }

        public ConnectionInfo ConnectionInformation
        {
            get { return _clientConnection; }
        }

        public AsynchronoiusIOClient()
        { }

        public AsynchronoiusIOClient(int serverPort)
        { _portOfServer = serverPort; }

        public AsynchronoiusIOClient(int serverPort, string localIP, string serverIP)
        { 
            _portOfServer = serverPort;
            _serverIP = serverIP;
            _localMachineIP = localIP;
           // SetupClientSocket();
        }

        private void SetupClientSocket()
        {
            _clientConnection = new ConnectionInfo();
            try
            {
                IPAddress remoteEPIP = IPAddress.Parse(_serverIP);
                IPAddress localEPIP = IPAddress.Parse(_localMachineIP);

                //Инфо о локальном компе
                IPEndPoint myEndPoint = new IPEndPoint(localEPIP, 0);

                //Информация о сервере.
                _remoteEndPoint = new IPEndPoint(remoteEPIP, _portOfServer);

                //Создаем сокет привязываем к адресу и слушаем.
                _clientSocket = new Socket(myEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                _clientSocket.Bind(myEndPoint);
                _clientConnection.ConnSocket = _clientSocket;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }            
        }

        private void ConnectCallback(IAsyncResult result)
        {
            try
            {
                _clientConnection.ConnSocket = _clientSocket;
            }
            catch (Exception ex)
            { Logger.WriteLog(String.Format("ConnectCallback error: {0}", ex.Message)); }
        }

        //Функция отправки сообщений серверу.
        public void Send(string Message)
        {
            byte[] bytesToSend = Encoding.ASCII.GetBytes(Message);
            //Encoding.ASCII.GetBytes(Message, 0, Message.Length, _clientConnection.Buffer, 0);
            _clientSocket.BeginSend(bytesToSend, 0, bytesToSend.Length, 0, 
                new AsyncCallback(SendCallback), _clientConnection);
        }

        private void SendCallback(IAsyncResult result)
        {
            try
            {
                int bytesSent = _clientConnection.ConnSocket.EndSend(result);
            }
            catch (Exception ex)
            { MessageBox.Show(ex.ToString()); }
        }

        //Прием сообщений от сервера. Полученные данные помещаются в recieveBuffer.
        public void Recieve()
        {
            _clientSocket.BeginReceive(_clientConnection.Buffer, 0, 
                ConnectionInfo.BufferSize, 0, 
                new AsyncCallback(RecieveCallback), _clientConnection);
        }

        private void RecieveCallback(IAsyncResult result)
        {
            try 
            {
                _clientConnection = (ConnectionInfo)result.AsyncState;
                Socket client = _clientConnection.ConnSocket;

                int bytesRead = _clientConnection.ConnSocket.EndReceive(result);
                _clientConnection.recieveBuffer = string.Empty;
                if (bytesRead > 0)
                {
                    _clientConnection.recieveBuffer = Encoding.ASCII.GetString(_clientConnection.Buffer, 0, bytesRead);

                    _clientSocket.BeginReceive(_clientConnection.Buffer, 0,
                        ConnectionInfo.BufferSize, SocketFlags.None, new AsyncCallback(RecieveCallback),
                        _clientConnection);
                }
                else
                {
                    if (_clientConnection.recieveBuffer.Length > 1)
                    {
                        MessageBox.Show(responce);
                        responce = _clientConnection.recieveBuffer;
                    }
                }
                //_clientConnection.Buffer = new byte[ConnectionInfo.BufferSize];
            }
            catch (SocketException se)
            {
                Logger.WriteLog(string.Format("SocketException: {0}",se.ToString()));
            }
            catch (Exception ex)
            {
                Logger.WriteLog(string.Format("Exception: {0}", ex.ToString()));
            }
        }

        public void CloseConnection()
        {
            _clientSocket.Close();
        }

        public void Start()
        {
                SetupClientSocket();
                _clientSocket.BeginConnect(_remoteEndPoint, new AsyncCallback(ConnectCallback), _clientConnection);
                Recieve();
        }        
    }
    public static class Logger
        {
            public static void WriteLog(string msg)
            {
                string[] s = new string[1];
                s[0] = string.Format("{0}: {1}", DateTime.Now.ToString(), msg);
                System.IO.File.AppendAllLines(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log.txt"), s);
            }
        }
}
